[id].vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. <script setup lang="ts" generic="T extends any, O extends any">
  2. import type { RouteLocationRaw } from 'vue-router'
  3. import request from '~/utils/request'
  4. // import { stepsMap } from '~/composables/steps'
  5. import { user } from '~/store/index'
  6. const props = defineProps<{
  7. id: string
  8. }>()
  9. const ykl_id = props.id
  10. const server = (await request({
  11. url: '/yzy/kmksyjlc/detail',
  12. data: {
  13. ykl_id,
  14. },
  15. })).data.one_info
  16. const isCreateUser = server.create_user_id === user.value.user_id
  17. const ykl_lc = Object.assign(JSON.parse(Object.assign(server.ykl_lc)), { ykl_id })
  18. console.log('ykl_lc : ', ykl_lc)
  19. sessionStorage.setItem('ykl_lc', JSON.stringify(ykl_lc))
  20. const stepsReactiveMap = reactive<unknown[][][]>(ykl_lc.processList)
  21. const steps = reactive(
  22. ykl_lc.ykj_yjlc === '1'
  23. ? [// 先上传后划块
  24. {
  25. title: '组卷考试',
  26. children: [
  27. {
  28. title: '出题组卷',
  29. children: [
  30. { title: '章节知识点出题', optional: true, disabled: true, description: '选择相应的章节知识点从题库中选取题目组成试卷', ifCreateUser: true },
  31. { title: '智能出题', optional: true, disabled: true, description: '填写题型数量难易度等信息系统自动生成试卷', ifCreateUser: true },
  32. { title: '附件出题', optional: true, description: '根据上传附件试卷进行考试', ifCreateUser: true },
  33. ],
  34. },
  35. {
  36. title: '预划考号区域',
  37. children: [
  38. { title: '预划考号区域', optional: false, description: '根据试题内容格式制作相应的答题卡样式', ifCreateUser: true },
  39. { title: '考场设置(可选)', optional: true, description: '根据学生考场分配情况上传' },
  40. ],
  41. },
  42. {
  43. title: '预划流程完成',
  44. children: [
  45. { title: '预划流程完成', optional: false, description: '试卷内容和答题卡已确认,可进行下一步', ifCreateUser: true },
  46. ],
  47. },
  48. ],
  49. },
  50. {
  51. title: '扫描',
  52. children: [
  53. {
  54. title: '答题卡扫描',
  55. children: [
  56. { title: '答题卡扫描', optional: false, description: '启动客户端扫描学生答题卡并进行识别与上传' },
  57. ],
  58. },
  59. {
  60. title: '压缩包上传情况',
  61. children: [
  62. { title: '压缩包上传情况', optional: false, description: '启动客户端扫描试卷形成压缩包打包上传平台' },
  63. ],
  64. },
  65. {
  66. title: '制作答题卡',
  67. children: [
  68. { title: '制作答题卡', optional: false, description: '根据试题内容格式制作相应的答题卡样式', ifCreateUser: true },
  69. ],
  70. },
  71. ],
  72. },
  73. {
  74. title: '制作扫描处理',
  75. children: [
  76. {
  77. title: '答题卡二次扫描',
  78. children: [
  79. { title: '答题卡二次扫描', optional: false, description: '启动客户端二次扫描批阅试卷' },
  80. ],
  81. },
  82. {
  83. title: '平台接收试卷确认',
  84. children: [
  85. { title: '平台接收试卷确认', optional: false, description: '确认试卷已上传' },
  86. ],
  87. },
  88. ],
  89. },
  90. {
  91. title: '阅卷',
  92. children: [
  93. {
  94. title: '批阅任务分配',
  95. children: [
  96. { title: '批阅任务分配', optional: false, description: '对阅卷老师分配批阅任务', ifCreateUser: true },
  97. ],
  98. },
  99. {
  100. title: '阅卷',
  101. children: [
  102. { title: '阅卷', optional: false, description: '查看批阅进度查看我的批阅任务' },
  103. ],
  104. },
  105. ],
  106. },
  107. {
  108. title: '成绩',
  109. children: [
  110. {
  111. title: '成绩发布',
  112. children: [
  113. { title: '成绩发布', optional: false, description: '成绩汇总发布到分析平台', ifCreateUser: true },
  114. ],
  115. },
  116. {
  117. title: '修改成绩',
  118. children: [
  119. { title: '修改成绩', optional: false, description: '考试成绩发布后三天内可修改', ifCreateUser: true },
  120. ],
  121. },
  122. {
  123. title: '考试关闭',
  124. children: [
  125. { title: '考试关闭', optional: false, description: '最后考试结束关闭考试', ifCreateUser: true },
  126. ],
  127. },
  128. ],
  129. },
  130. ]
  131. : [// 先划块后上传
  132. {
  133. title: '组卷考试',
  134. children: [
  135. {
  136. title: '出题组卷',
  137. children: [
  138. { title: '章节知识点出题', optional: true, disabled: true, description: '选择相应的章节知识点从题库中选取题目组成试卷', ifCreateUser: true },
  139. { title: '智能出题', optional: true, disabled: true, description: '填写题型数量难易度等信息系统自动生成试卷', ifCreateUser: true },
  140. { title: '附件出题', optional: true, description: '根据上传附件试卷进行考试', ifCreateUser: true },
  141. ],
  142. },
  143. {
  144. title: '制作答题卡',
  145. children: [
  146. { title: '制作答题卡', optional: false, description: '根据试题内容格式制作相应的答题卡样式', ifCreateUser: true },
  147. { title: '考场设置(可选)', optional: true, description: '根据学生考场分配情况上传' },
  148. ],
  149. },
  150. {
  151. title: '组卷流程完成',
  152. children: [
  153. { title: '组卷流程完成', optional: false, description: '试卷内容和答题卡已确认,可进行下一步', ifCreateUser: true },
  154. ],
  155. },
  156. ],
  157. },
  158. {
  159. title: '扫描',
  160. children: [
  161. {
  162. title: '答题卡扫描',
  163. children: [
  164. { title: '连接扫描仪', optional: false, description: '启动客户端扫描学生答题卡并进行识别与上传' },
  165. ],
  166. },
  167. {
  168. title: '平台接收试卷确认',
  169. children: [
  170. { title: '平台接收试卷确认', optional: false, description: '时间及试题均接收并识别入库完成' },
  171. ],
  172. },
  173. ],
  174. },
  175. {
  176. title: '阅卷',
  177. children: [
  178. {
  179. title: '批阅任务分配',
  180. children: [
  181. { title: '批阅任务分配', optional: false, description: '对阅卷老师分配批阅任务', ifCreateUser: true },
  182. ],
  183. },
  184. {
  185. title: '阅卷',
  186. children: [
  187. { title: '阅卷', optional: false, description: '查看批阅进度查看我的批阅任务' },
  188. ],
  189. },
  190. ],
  191. },
  192. {
  193. title: '成绩',
  194. children: [
  195. {
  196. title: '成绩发布',
  197. children: [
  198. { title: '成绩发布', optional: false, description: '成绩汇总发布到分析平台', ifCreateUser: true },
  199. ],
  200. },
  201. {
  202. title: '修改成绩',
  203. children: [
  204. { title: '修改成绩', optional: false, description: '考试成绩发布后三天内可修改', ifCreateUser: true },
  205. ],
  206. },
  207. {
  208. title: '考试关闭',
  209. children: [
  210. { title: '考试关闭', optional: false, description: '最后考试结束关闭考试', ifCreateUser: true },
  211. ],
  212. },
  213. ],
  214. },
  215. ],
  216. )
  217. let gid = $ref<number>(0)
  218. let pids = $ref<number[]>([])
  219. // const cid = $ref(-1)
  220. function getGid() {
  221. return stepsReactiveMap.findLastIndex(item => item.some(subItem => subItem.some(subSubItem => judgeStepCompleted(subSubItem))))
  222. }
  223. function getPids() {
  224. return stepsReactiveMap.map((item, idx) => (idx < gid ? 1 : 0) + item.findLastIndex(subItem => subItem.some(subSubItem => judgeStepCompleted(subSubItem))))
  225. }
  226. watch(() => stepsReactiveMap, (val) => {
  227. gid = getGid()
  228. pids = getPids()
  229. }, {
  230. immediate: true,
  231. deep: true,
  232. })
  233. let currentStep = $ref<number>(gid)
  234. const CardsRef = $shallowRef<Array<Array<typeof import('~/components/TheCard.vue')['default']>>>([])
  235. const lineList: any[][][] = []
  236. // onMounted(() => {
  237. // CardsRef.forEach((cards, idx) => {
  238. // if (idx === CardsRef.length - 1)
  239. // return
  240. // cards.forEach((card, idy) => {
  241. // const line = new LeaderLine(
  242. // card.getDom(),
  243. // CardsRef[idx + 1][0].getDom(),
  244. // {
  245. // path: 'grid',
  246. // endPlug: 'behind',
  247. // size: 6,
  248. // startSocket: 'right',
  249. // endSocket: 'left',
  250. // color: stepsReactiveMap[currentStep][idx][idy] ? '#003eee' : '#a3a3a3',
  251. // },
  252. // )
  253. // lineList.push(line)
  254. // })
  255. // })
  256. // })
  257. function handleSwitchCurrentStep(id: number) {
  258. currentStep = id
  259. }
  260. onMounted(() => {
  261. watch(() => currentStep, (val, old) => {
  262. if (old !== undefined)
  263. lineList[old].forEach(lines => lines.forEach(line => line?.hide('none')))
  264. if (lineList[val]?.length) {
  265. lineList[val].forEach(lines => lines.forEach(line => line?.show('none')))
  266. }
  267. else {
  268. nextTick(() => {
  269. CardsRef.forEach((cards, idx) => {
  270. if (idx === CardsRef.length - 1)
  271. return
  272. cards.forEach((card, idy) => {
  273. if (card === null || CardsRef[idx + 1][0] === null)
  274. return
  275. const line = new LeaderLine(
  276. card.getDom(),
  277. CardsRef[idx + 1][0].getDom(),
  278. {
  279. path: 'grid',
  280. endPlug: 'behind',
  281. size: 6,
  282. startSocket: 'right',
  283. endSocket: 'left',
  284. color: stepsReactiveMap[currentStep][idx][idy] ? '#003eee' : '#a3a3a3',
  285. },
  286. )
  287. line?.position()
  288. if (stepsReactiveMap[currentStep][idx][idy])
  289. document.querySelectorAll('.leader-line')[line._id as number - 1]?.classList.add('z10')
  290. lineList[val] = lineList[val] || []
  291. lineList[val][idx] = lineList[val][idx] || []
  292. lineList[val][idx][idy] = line
  293. })
  294. })
  295. })
  296. }
  297. }, {
  298. immediate: true,
  299. })
  300. })
  301. const router = useRouter()
  302. function routerPush(path: RouteLocationRaw) {
  303. router.push(path)
  304. }
  305. function windowPushState(path: string) {
  306. // ! 未启用
  307. sessionStorage.setItem('historyLocation', location.href)
  308. window.open(`${location.origin}/${path}`, '_self')
  309. // location.replace(`${location.origin}/${path}`)
  310. // window.history.pushState(null, '', `${location.origin}/${path}`)
  311. }
  312. // 采取如下方式主要由于chrome下history.back()不会重新load页面
  313. window.addEventListener('pageshow', (e) => {
  314. if (e.persisted)
  315. window.location.reload()
  316. })
  317. function handleValidTask(currentStep: number, idx: number, idy: number) {
  318. let lastIdx = idx
  319. let lastStep = currentStep
  320. const lastTasks = idx > 0 ? stepsReactiveMap[currentStep][lastIdx = idx - 1] : currentStep > 0 ? stepsReactiveMap[lastStep = currentStep - 1][lastIdx = stepsReactiveMap[currentStep - 1].length - 1] : []
  321. if (lastTasks.every((item, idz) => {
  322. if (steps[lastStep].children[lastIdx].children[idz].optional)
  323. return true
  324. else
  325. return !!item
  326. })) {
  327. sessionStorage.setItem('StepId', JSON.stringify({ gid: currentStep, pid: idx, cid: idy }))
  328. return true
  329. }
  330. else {
  331. ElMessage({
  332. message: '请先完成之前的任务',
  333. type: 'warning',
  334. grouping: true,
  335. })
  336. return false
  337. }
  338. }
  339. function judgeIfContinueDoTask(gid: number, pid: number, idy: number) {
  340. const currentTask = steps[gid].children[pid].children[idy]
  341. const continueDoTask = !currentTask.ifCreateUser || isCreateUser
  342. if (!continueDoTask) {
  343. ElMessage({
  344. message: '只有考试创建人才能操作',
  345. type: 'warning',
  346. grouping: true,
  347. })
  348. }
  349. return continueDoTask
  350. }
  351. function beforeClickTask(gid: number, pid: number, idy: number) {
  352. const continueDoTask = judgeIfContinueDoTask(gid, pid, idy)
  353. if (!continueDoTask)
  354. return false
  355. else
  356. return handleValidTask(gid, pid, idy)
  357. }
  358. function judgeTaskCanClick(gid: number, pid: number, idy: number) {
  359. const continueDoTask = judgeIfContinueDoTask(gid, pid, idy)
  360. if (!continueDoTask) {
  361. return false
  362. }
  363. else {
  364. let lastIdx = pid
  365. let lastStep = currentStep
  366. const lastTasks = pid > 0 ? stepsReactiveMap[currentStep][lastIdx = pid - 1] : currentStep > 0 ? stepsReactiveMap[lastStep = currentStep - 1][lastIdx = stepsReactiveMap[currentStep - 1].length - 1] : []
  367. if (lastTasks.every((item, idz) => {
  368. if (steps[lastStep].children[lastIdx].children[idz].optional)
  369. return true
  370. else
  371. return !!item
  372. }))
  373. return true
  374. else
  375. return false
  376. }
  377. }
  378. function judgeStepCompleted(val: unknown) {
  379. return (!!val) || (typeof val === 'object' && !!(val?.value))
  380. }
  381. function handleCompleteTask(gid: number, pid: number, cid: number, val?: unknown, ext?: any): Promise<any> {
  382. const _ykl_lc_ = JSON.parse(sessionStorage.getItem('ykl_lc')!)
  383. _ykl_lc_.processList[gid][pid][cid] = val || 1
  384. const reqData: any = {
  385. ykl_id,
  386. yk: {
  387. ykl_lc: JSON.stringify(_ykl_lc_),
  388. },
  389. }
  390. // 把ext上的属性合并到reqData上,考虑嵌套的情况
  391. if (ext) {
  392. Object.keys(ext).forEach((key) => {
  393. if (typeof ext[key] === 'object') {
  394. if (reqData[key]) {
  395. reqData[key] = {
  396. ...reqData[key],
  397. ...ext[key],
  398. }
  399. }
  400. else { reqData[key] = ext[key] }
  401. }
  402. else {
  403. reqData[key] = ext[key]
  404. }
  405. })
  406. }
  407. return request({
  408. url: '/yzy/kmksyjlc/save',
  409. data: reqData,
  410. }).then((res) => {
  411. if (res.code === '1') {
  412. ElMessage({
  413. message: '操作成功',
  414. type: 'success',
  415. grouping: true,
  416. })
  417. sessionStorage.setItem('ykl_lc', JSON.stringify(_ykl_lc_))
  418. stepsReactiveMap[gid][pid][cid] = val || 1
  419. return res
  420. }
  421. }).catch(() => {
  422. ElMessage({
  423. message: '操作失败',
  424. type: 'error',
  425. grouping: true,
  426. })
  427. })
  428. }
  429. async function handleJumpTask(gid: number, pid: number, idy: number, ext?: object) {
  430. // 验证任务是否完成
  431. if (judgeStepCompleted(stepsReactiveMap[gid][pid][idy])) {
  432. return ElMessage({
  433. message: '该任务已完成',
  434. type: 'warning',
  435. grouping: true,
  436. })
  437. }
  438. // stepsReactiveMap[gid][pid][idy] = 1
  439. const res = await handleCompleteTask(gid, pid, idy, 1, ext)
  440. if (res.code === '1') {
  441. if (pid !== stepsReactiveMap[gid].length - 1) {
  442. const line = lineList[gid][pid][idy]
  443. line.setOptions({ color: '#003eee' })
  444. document.querySelectorAll('.leader-line')[line._id - 1]?.classList.add('z10')
  445. }
  446. }
  447. return res
  448. }
  449. onBeforeRouteLeave(() => {
  450. lineList.forEach(lines => lines.forEach(line => line.forEach(l => l?.hide('none'))))
  451. })
  452. function handleCompleteTaskAuto(ext?: object) {
  453. const { gid, pid, cid } = JSON.parse(sessionStorage.getItem('StepId')!)
  454. return handleJumpTask(gid, pid, cid, ext)
  455. }
  456. const TaskEventMap: { [key: string]: () => void } = {
  457. '章节知识点出题': () => {
  458. ElMessage.info('暂未开放')
  459. },
  460. '智能出题': () => {
  461. ElMessage.info('暂未开放')
  462. },
  463. '附件出题': () => {
  464. routerPush({ name: 'process-fjct-ze_id-zs_id', params: { ze_id: ykl_lc.ze_id, zs_id: ykl_lc.zs_id } })
  465. },
  466. '预划考号区域': () => {
  467. windowPushState(`${window.GLOBAL_CONFIG.build}/dtk/index.html`)
  468. },
  469. '制作答题卡': () => {
  470. windowPushState(`${window.GLOBAL_CONFIG.build}/dtk/index.html`)
  471. },
  472. '考场设置(可选)': () => {
  473. windowPushState(`${window.GLOBAL_CONFIG.base}/exam-room-set.html?id=${ykl_lc.ze_id}`)
  474. },
  475. '预划流程完成': async () => {
  476. await handleCompleteTaskAuto()
  477. currentStep = 1
  478. },
  479. '组卷流程完成': async () => {
  480. await handleCompleteTaskAuto()
  481. currentStep = 1
  482. },
  483. // 先上传后划块
  484. '答题卡扫描': () => {
  485. window.open(`BozeduYuejuan://${user.value.token},${ykl_lc.ze_id},${window.GLOBAL_CONFIG.yzy},upload_papers`, '_blank')
  486. handleCompleteTaskAuto()
  487. },
  488. '压缩包上传情况': async () => {
  489. await handleCompleteTaskAuto()
  490. // TODO: 需调整【压缩包】上传情况
  491. routerPush(`/process/ysb/${ykl_lc.ykl_id}/${ykl_lc.ze_id}`)
  492. },
  493. '答题卡二次扫描': () => {
  494. window.open(`BozeduYuejuan://${user.value.token},${ykl_lc.ze_id},${window.GLOBAL_CONFIG.yzy},review_papers`, '_blank')
  495. handleCompleteTaskAuto()
  496. },
  497. // 先划块后上传 老流程
  498. '连接扫描仪': () => {
  499. window.open(`BozeduYuejuan://${user.value.token},${ykl_lc.ze_id},${window.GLOBAL_CONFIG.yzy}`, '_blank')
  500. handleCompleteTaskAuto()
  501. },
  502. '平台接收试卷确认': async () => {
  503. await handleCompleteTaskAuto()
  504. windowPushState(`${window.GLOBAL_CONFIG.base}/marking-answer-sheet-liankao.html?ze_id=${ykl_lc.ze_id}`)
  505. },
  506. '批阅任务分配': () => {
  507. windowPushState(`${window.GLOBAL_CONFIG.base}/taskassignment-liankao.html`)
  508. },
  509. '阅卷': async () => {
  510. await handleCompleteTaskAuto()
  511. // todo: 需调整【阅卷】
  512. windowPushState(`${window.GLOBAL_CONFIG.base}/single-review-liankao.html?ze_id=${ykl_lc.ze_id}`)
  513. },
  514. '成绩发布': () => {
  515. let loading = false
  516. ElMessageBox.confirm('选择实时发布时需等待浏览器处理结束;正常发布则无需等待', '选择发布成绩的方式', {
  517. confirmButtonText: '实时发布',
  518. cancelButtonText: '正常发布',
  519. type: 'info',
  520. distinguishCancelAndClose: true,
  521. beforeClose: async (action, instance, done) => {
  522. if (action === 'confirm') {
  523. // 实时发布
  524. console.log('实时发布')
  525. instance.confirmButtonLoading = loading = true
  526. try {
  527. const res0 = await request({
  528. url: '/openapi/crontab/datamaker.php',
  529. data: {
  530. ykl_id,
  531. },
  532. })
  533. if (res0.code !== '1')
  534. throw new Error(res0.msg)
  535. const res1 = await handleCompleteTaskAuto({ force: 1 })
  536. if (res1.code !== '1')
  537. throw new Error(res1.msg)
  538. ykl_lc.ykl_stat_ready = 2
  539. ElMessage.success('发布成功')
  540. }
  541. catch (error) {
  542. console.error('发布失败', error)
  543. }
  544. instance.confirmButtonLoading = loading = false
  545. }
  546. else if (action === 'cancel') {
  547. // 正常发布
  548. console.log('正常发布')
  549. instance.cancelButtonLoading = loading = true
  550. try {
  551. // const res0 = await request({
  552. // url: '/yzy/kmksyjlc/save',
  553. // data: {
  554. // ykl_id,
  555. // yk: {
  556. // ykl_sffbcj: 1,
  557. // },
  558. // },
  559. // })
  560. // if (res0.code !== '1')
  561. // throw new Error(res0.msg)
  562. const res1 = await handleCompleteTaskAuto({
  563. force: 1,
  564. yk: {
  565. ykl_sffbcj: 1,
  566. },
  567. })
  568. if (res1.code !== '1')
  569. throw new Error(res1.msg)
  570. ykl_lc.ykl_stat_ready = 1
  571. ElMessage.success('发布中...')
  572. }
  573. catch (error) {
  574. console.error('发布失败', error)
  575. }
  576. instance.cancelButtonLoading = loading = false
  577. }
  578. else {
  579. console.log('取消发布')
  580. return loading ? ElMessage.warning('发布中,请勿关闭弹窗') : done()
  581. }
  582. },
  583. })
  584. },
  585. '修改成绩': async () => {
  586. await handleCompleteTaskAuto()
  587. routerPush({ name: 'process-xgcj-id', params: { id: ykl_lc.ze_id } })
  588. },
  589. '考试关闭': () => {
  590. ElMessageBox({
  591. title: '提示',
  592. message: '确定要关闭考试吗?',
  593. type: 'warning',
  594. showCancelButton: true,
  595. confirmButtonText: '确定',
  596. cancelButtonText: '取消',
  597. }).then(() => {
  598. const { gid, pid, cid } = JSON.parse(sessionStorage.getItem('StepId')!)
  599. handleJumpTask(gid, pid, cid)
  600. })
  601. },
  602. }
  603. </script>
  604. <template>
  605. <div class="w-full min-h-screen flex flex-col bg-white">
  606. <NavHeader />
  607. <bread-crumb />
  608. <div class="flex-auto w-1200px m-auto">
  609. <div class="flex flex-auto justify-start divide-x-4 divide-blue-700">
  610. <div class="h-full w-220px">
  611. <el-steps direction="vertical" :active="currentStep">
  612. <el-step
  613. v-for="({ title, children }, idx) in steps" :key="title" class="cursor-pointer hover:bg-light-600"
  614. :class="idx === currentStep && 'bg-light-400'" @click="handleSwitchCurrentStep(idx)"
  615. >
  616. <template #title>
  617. <div class="mb-4 font-normal">
  618. {{ title }}
  619. </div>
  620. </template>
  621. <template #description>
  622. <el-steps direction="vertical" :space="40" :active="pids[idx]">
  623. <el-step v-for="({ title }) in children" :key="title">
  624. <template #title>
  625. <div class="font-normal">
  626. {{ title }}
  627. </div>
  628. </template>
  629. </el-step>
  630. </el-steps>
  631. </template>
  632. </el-step>
  633. </el-steps>
  634. </div>
  635. <div class="flex-auto p-4">
  636. <div class="h-full flex justify-between">
  637. <div
  638. v-for="(step, idx) in steps[currentStep].children " :key="idx"
  639. class="h-full flex flex-col justify-evenly"
  640. >
  641. <the-card
  642. v-for="(task, idy) in step.children " :key="idy"
  643. :ref="el => { CardsRef[idx] = CardsRef[idx] || []; CardsRef[idx][idy] = el as any }" :title="task.title"
  644. :description="task.description" :completed="judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy])"
  645. >
  646. <template #operate>
  647. <template v-if="task.title === '预划考号区域'">
  648. <div
  649. class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
  650. @click="beforeClickTask(currentStep, idx, idy) && TaskEventMap[task.title]()"
  651. >
  652. {{ judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy]) ? '已经完成' : '立即开始' }}
  653. </div>
  654. <div
  655. class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
  656. @click="beforeClickTask(currentStep, idx, idy) && handleJumpTask(currentStep, idx, idy)"
  657. >
  658. {{ '跳过' }}
  659. </div>
  660. </template>
  661. <template v-else-if="task.title === '成绩发布'">
  662. <div
  663. class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
  664. @click="beforeClickTask(currentStep, idx, idy) && (TaskEventMap[task.title] ? TaskEventMap[task.title]() : handleCompleteTaskAuto())"
  665. >
  666. {{ judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy])
  667. ? (ykl_lc.ykl_stat_ready === 1 ? '发布中…' : '已发布') : '成绩发布' }}
  668. </div>
  669. </template>
  670. <template v-else>
  671. <div
  672. class="min-w-60px rounded bg-light-50 py-3px text-center text-xs"
  673. :class="task.disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
  674. @click="beforeClickTask(currentStep, idx, idy) && (TaskEventMap[task.title] ? TaskEventMap[task.title]() : handleCompleteTaskAuto())"
  675. >
  676. {{ judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy]) ? '已经完成' : task.disabled ? '暂未开放'
  677. : '立即开始'
  678. }}
  679. </div>
  680. </template>
  681. </template>
  682. <template #tip>
  683. <template v-if="task.title === '成绩发布'">
  684. <div class="mt-2 flex flex-col items-start px-1 text-xs space-y-1" style="--el-font-size-base:10px">
  685. <xgstda :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
  686. <szcjckqx :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
  687. <bjqk :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
  688. </div>
  689. </template>
  690. </template>
  691. </the-card>
  692. </div>
  693. </div>
  694. </div>
  695. </div>
  696. </div>
  697. <commonFooter />
  698. </div>
  699. </template>
  700. <style scoped>
  701. :deep(.el-step:last-of-type .el-step__line) {
  702. display: block;
  703. }
  704. :deep(.el-step__description .el-step:last-of-type .el-step__line) {
  705. display: none;
  706. }
  707. </style>
  708. <route>
  709. {
  710. meta: {
  711. title: '考试流程',
  712. breadcrumb: true,
  713. },
  714. }
  715. </route>